/*   Copyright 2012 Julian Aloofi

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "ResourceManager.hpp"

Tacticus::ResourceManager *Tacticus::ResourceManager::instance = 0;

Tacticus::ResourceManager &Tacticus::ResourceManager::getInstance()
{
    if (!instance)
        instance  = new ResourceManager();
    return *instance;
}

void Tacticus::ResourceManager::destroy()
{
    if (instance)
        delete instance;
    instance = 0;
}

void Tacticus::ResourceManager::setFilesystemBasePath(
    std::string newFilesystemBasePath)
{
    filesystemBasePath = newFilesystemBasePath;
}

boost::shared_ptr<sf::Sprite> Tacticus::ResourceManager::getSprite(
    std::string textureName) const
{
    if (!resourcesLoaded)
    {
        throw Common::ResourceException("Resources not loaded yet!");
    }
    boost::shared_ptr<sf::Sprite> retSprite(new sf::Sprite());

    bool wantsSmall = false;
    std::map<std::string, float>::const_iterator findSmall;
    if (textureName.compare(textureName.length() - smallSuffix.length(),
        smallSuffix.length(), smallSuffix) == 0)
    {
        textureName.erase(textureName.length() - smallSuffix.length());
        findSmall = smallTextureMap.find(textureName);
        wantsSmall = true;
        if (findSmall == smallTextureMap.end())
        {
            throw Common::ResourceException("No small texture available for " +
                textureName);
        }
    }

    std::map<std::string, sf::Texture>::const_iterator findIt =
        textureMap.find(textureName);
    if (findIt == textureMap.end())
    {
        throw Common::ResourceException("Could not find texture " +
            textureName);
    }
    else
    {
        retSprite->setTexture(findIt->second);
        retSprite->setScale(neededSpriteScale);
        if (wantsSmall)
        {
            retSprite->scale(findSmall->second, findSmall->second);
        }
    }
    return retSprite;
}

boost::shared_ptr<sf::Text> Tacticus::ResourceManager::renderText(
    std::string desiredText, int textSize) const
{
    boost::shared_ptr<sf::Text> retText(new sf::Text(desiredText, mainFont,
        textSize));
    retText->setColor(sf::Color(210, 210, 13));
    retText->setScale(neededSpriteScale);
    return retText;
}

void Tacticus::ResourceManager::loadResources()
{
    if (!WindowManager::getInstance().isMainWindowCreated())
    {
        throw Common::ResourceException(
            "The main window needs to be created before loading resources");
    }

    const sf::Vector2u &windowSize = WindowManager::getInstance().
        getMainWindow().getSize();
    // all textures are sized as if the screen was 2160x1800
    const sf::Vector2u textureSize(2160, 1800);
    neededSpriteScale.x = (float) windowSize.x / (float) textureSize.x;
    neededSpriteScale.y = (float) windowSize.y / (float) textureSize.y;

    using namespace boost::property_tree;
    ptree xmlRoot;
    read_xml(filesystemBasePath + "Resources.xml", xmlRoot);

    ptree textures = xmlRoot.get_child("Resources.Textures");
    for (ptree::const_iterator it = textures.begin(); it != textures.end();
        it++)
    {
        textureMap[it->first] = sf::Texture();
        textureMap[it->first].loadFromFile(filesystemBasePath + "Textures/" +
            it->second.data());

        boost::optional<float> smallCopySize = textures.get_optional<float>(
            it->first + ".<xmlattr>.smallCopySize");
        if (smallCopySize)
        {
            smallTextureMap[it->first] = *smallCopySize;
        }
    }

    mainFont.loadFromFile(filesystemBasePath + xmlRoot.get<std::string>(
        "Resources.Fonts.MainFont"));

    resourcesLoaded = true;
}

void Tacticus::ResourceManager::unloadResources()
{
    textureMap.clear();
    resourcesLoaded = false;
}

Tacticus::ResourceManager::ResourceManager() : filesystemBasePath("resources/"),
    resourcesLoaded(false), smallSuffix(":Small")
{
}

Tacticus::ResourceManager::~ResourceManager()
{
    unloadResources();
}
